package com.axzhengxin.platform.afterloan.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.axzhengxin.platform.afterloan.controller.RiskModelCallbackController.RiskModelCallbackRequest;
import com.axzhengxin.platform.afterloan.domain.RiskModelResult;
import com.axzhengxin.platform.afterloan.domain.RiskSignalTableData;
import com.axzhengxin.platform.afterloan.domain.WarnSignalLog;
import com.axzhengxin.platform.afterloan.mapper.FspCorInfMapper;
import com.axzhengxin.platform.afterloan.mapper.RiskModelResultMapper;
import com.axzhengxin.platform.afterloan.service.IRiskModelService;
import com.axzhengxin.platform.afterloan.transf.RiskDataDetail;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * RiskModelServiceImpl
 *
 * @author jiangnan
 * @date 2021/3/17
 */
@Slf4j
@Service
public class RiskModelServiceImpl implements IRiskModelService {

    private RiskModelResultMapper riskModelResultMapper;

    private FspCorInfMapper fspCorInfMapper;


    public RiskModelServiceImpl(RiskModelResultMapper riskModelResultMapper,
                                FspCorInfMapper fspCorInfMapper) {
        this.riskModelResultMapper = riskModelResultMapper;
        this.fspCorInfMapper = fspCorInfMapper;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void handleCallback(@Nullable RiskModelCallbackRequest request) {
        // 第一步，拆解响应报文，重新按照规则ID分级
        List<RiskModelResult> results = parsedResult(request);
        // 第二步，保存结果
        results.forEach(riskModelResultMapper::insertRiskModelResult);
        // 第三步，统计并更新统计结果
        updateWarnSignalLog(results);
    }

    private List<RiskModelResult> parsedResult(@Nullable RiskModelCallbackRequest request) {
        return Optional.ofNullable(request)
                .map(RiskModelCallbackRequest::getResult)
                .filter(CollUtil::isNotEmpty)
                .map(results -> results.stream()
                        .map(this::parsedResult)
                        .flatMap(List::stream)
                        .collect(Collectors.toList()))
                .orElse(new ArrayList<>());
    }

    /**
     * 解析推送的预警结果
     *
     * @param originResult 原始预警结果，一个记录中有该企业触发的所有预警信号
     * @return 拆解后的预警结果，每个元素代表一个触发的预警信号
     */
    private List<RiskModelResult> parsedResult(RiskModelResult originResult) {
        String[] detailArr = Optional.ofNullable(originResult.getBatchDetail())
                .map(detail -> detail.split(","))
                .orElse(new String[0]);
        AtomicInteger indexRef = new AtomicInteger(0);
        return Stream.of(originResult.getBatchRules())
                .filter(StrUtil::isNotBlank)
                .flatMap(rules -> Stream.of(rules.split(",")))
                .map(rule -> {
                    int index = indexRef.getAndIncrement();
                    RiskModelResult result = new RiskModelResult();
                    BeanUtils.copyProperties(originResult, result, "batchDetail", "batchRules");
                    if (detailArr.length > index) {
                        result.setBatchDetail(detailArr[index]);
                    }
                    result.setBatchRules(rule);
                    if (rule.contains(":")
                            && !rule.endsWith(":")) {
                        result.setBatchRuleCode(rule.substring(0, rule.indexOf(":")));
                        result.setBatchRuleName(rule.substring(rule.indexOf(":") + 1));
                    }
                    Optional.ofNullable(DictUtils.getDictCache("warn_signal"))
                            .flatMap(dictDataList -> dictDataList.stream()
                                    .filter(data -> result.getBatchRuleCode().contains(data.getDictValue()))
                                    .findFirst())
                            .map(SysDictData::getRemark)
                            .ifPresent(result::setRuleLevel);
                    return result;
                })
                .collect(Collectors.toList());
    }

    private void updateWarnSignalLog(List<RiskModelResult> results) {
        results.stream()
                // 按企业名称分组
                .collect(Collectors.groupingBy(RiskModelResult::getEntName))
                .entrySet()
                .stream()
                // 过滤掉没有值的组，虽然理论上不可能有
                .filter(entry -> Objects.nonNull(entry.getValue()))
                // 转为企业名称-信号数量
                .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().size()))
                // 转为企业信息-信号数量
                .map(entry -> new AbstractMap.SimpleEntry<>(fspCorInfMapper.selectFspCorInfByName(entry.getKey()), entry.getValue()))
                // 过滤掉没查到企业信息的情况
                .filter(entry -> Objects.nonNull(entry.getKey()))
                // 按企业ID和预警信号数更新统计表
                .forEach(entry -> {
                    if (riskModelResultMapper.updateWarnSignalLog(entry.getKey().getId(), entry.getValue()) <= 0) {
                        WarnSignalLog warnSignalLog = new WarnSignalLog();
                        warnSignalLog.setCustomerId(entry.getKey().getId());
                        warnSignalLog.setSignalCount(entry.getValue());
                        riskModelResultMapper.insertWarnSignalLog(warnSignalLog);
                    }
                });

    }

    @Override
    public List<RiskDataDetail> warnList(String customerId) {
        AtomicInteger index = new AtomicInteger(0);
        return riskModelResultMapper.queryRiskDataList(customerId)
                .stream()
                .map(RiskDataDetail::init)
                .peek(data -> data.setIndex(index.incrementAndGet()))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int disableWarnSignal(Integer id) {
        return Optional.of(riskModelResultMapper.disableWarnSignal(id))
                .filter(rows -> rows > 0)
                .map(row -> riskModelResultMapper.selectCustomerIdByWarnSignalId(id))
                .filter(StrUtil::isNotBlank)
                .map(customerId -> riskModelResultMapper.updateWarnSignalLog(customerId, -1))
                .orElse(0);
    }

    private static final Map<String, String> RISK_LEVEL_MAPPER = MapUtil
            .<String, String>builder()
            .put("一级", "1")
            .put("二级", "2")
            .put("三级", "3")
            .build();
    private static final Map<String, String> RISK_LEVEL_MAPPER_REVERSE = MapUtil
            .<String, String>builder()
            .put("1", "一级")
            .put("2", "二级")
            .put("3", "三级")
            .build();

    @DataScope(userAlias = "u", deptAlias = "d")
    @Override
    public List<RiskSignalTableData> selectRiskSignalList(@NotNull RiskSignalTableData data) {
        // 转换规则等级
        Optional.of(data)
                .map(RiskSignalTableData::getRuleLevel)
                .filter(StrUtil::isNotBlank)
                .filter(RISK_LEVEL_MAPPER_REVERSE::containsKey)
                .map(RISK_LEVEL_MAPPER_REVERSE::get)
                .ifPresent(data::setRuleLevel);
        // 再次转换规则等级
        List<RiskSignalTableData> riskSignalTableData = selectRiskSignalListByBizSource(data);
        for (RiskSignalTableData result : riskSignalTableData) {
            result.setRuleLevel(RISK_LEVEL_MAPPER.get(result.getRuleLevel()));
            if (Objects.nonNull(result.getSignalCount()) && result.getSignalCount() > 0) {
                result.setSignStatus(DictUtils.getDictValue("signal_status", "未查看"));
            } else {
                result.setSignStatus(DictUtils.getDictValue("signal_status", "已查看"));
            }
        }
        return riskSignalTableData;
       /* return riskSignalTableData
                .stream()
                .peek(result -> result.setRuleLevel(RISK_LEVEL_MAPPER.get(result.getRuleLevel())))
                .peek(result -> {
                    if (Objects.nonNull(result.getSignalCount()) && result.getSignalCount() > 0) {
                        result.setSignStatus(DictUtils.getDictValue("signal_status", "未查看"));
                    } else {
                        result.setSignStatus(DictUtils.getDictValue("signal_status", "已查看"));
                    }
                })
                .collect(Collectors.toList());*/
    }

    /**
     * 根据输入的查询参数中的业务数据来源字段，分别进行查询
     *
     * @param data 查询参数
     * @return 结果集合
     */
    private List<RiskSignalTableData> selectRiskSignalListByBizSource(@NotNull RiskSignalTableData data) {
        return Optional.of(data)
                .map(RiskSignalTableData::getBizSource)
                .filter(StrUtil::isNotBlank)
                .map(bizSource -> {
                    // 选择了"全部"数据来源
                    if ("-1".equalsIgnoreCase(bizSource)) {
                        return riskModelResultMapper.selectRiskSignalListAll(data);
                    } else if ("0".equalsIgnoreCase(bizSource)) {
                        // "内部流转"
                        return riskModelResultMapper.selectRiskSignalList(data);
                    } else if ("1".equalsIgnoreCase(bizSource)) {
                        // "批量上传"
                        return riskModelResultMapper.selectRiskSignalListUpload(data);
                    } else {
                        // 其他不合法的值
                        return new ArrayList<RiskSignalTableData>();
                    }
                }).orElse(riskModelResultMapper.selectRiskSignalListAll(data));
    }

    @Override
    public void disableWarnSignal(String customerId) {
        riskModelResultMapper.disableWarnSignalByCustomerId(customerId);
        riskModelResultMapper.clearWarnSignalLog(customerId);
    }



}
